//+--------------------------------------------------------------------------------
//| Copyright (c) 2012 - 2013 ### an.vuongngocduy
//| This file is a part of Compact Game Engine (CGE)
//+--------------------------------------------------------------------------------
#ifndef __CGE_VECTOR2_H__
#define __CGE_VECTOR2_H__

#include "cgeCommons.h"
#include "cgeMath.h"

namespace cge
{
	namespace std
	{
		/*! Vector2<T> template class . 
		 *	Used as a 2-dimensional direction vector or position of 2-dimensional point .
		 */
		template<class TVal>
		class Vector2
		{
		public:
			//! Default constructor
			Vector2()
				: X(0), Y(0)
			{}
			
			
			//! Copy constructor
			Vector2(const Vector2& sz)
				: X(sz.X), Y(sz.Y)
			{}

			
			//! Construct vector from specified values
			Vector2(TVal x, TVal y)
				: X(x), Y(y)
			{}

			
			//! Destructor
			~Vector2(){}

			
			//! Set vector coordinates from sepcified values
			void Set(TVal x, TVal y)
			{
				X = x;	Y = y;
			}


			//! Return length of vector
			f32 Length() const
			{
				return Math::Sqrt(X * X + Y * Y);
			}


			//! Return squared length of vector
			f32 LengthSquared() const
			{
				return (X * X + Y * Y);
			}


			//! Canculate the dot product of 2 vectors
			f32 Dot(const Vector2& v2) const
			{
				return (X * v2.X + Y * v2.Y);
			}


			//! Canculate the angle between 2 vectors
			f32 AngleBetween(const Vector2& v2) const
			{
				return Math::Acos(Dot(v2) / Math::Sqrt((X*X + Y*Y) * (v2.X*v2.X + v2.Y*v2.Y)));
			}


			//! Do vector normalization
			Vector2& Normalize()
			{
				f32 len = Length();
				X /= len;	Y /= len;
				return *this;
			}

			Vector2 Normalize() const
			{
				f32 len = Length();
				return Vector2(X / len , Y / len);
			}


			//! Multiply vector's coordinates with a scalar
			template<class TArg>
			Vector2 operator * (TArg scalar) const
			{
				return Vector2(X * scalar, Y * scalar);
			}


			//! Divide vector's coordinates by a scalar
			template<class TArg>
			Vector2 operator / (TArg scalar) const
			{
				return Vector2(X / scalar, Y / scalar);
			}


			//! Negate vector
			Vector2 operator - (void) const
			{
				return Vector2(-X, -Y);
			}


			//! Add 2 vectors together
			Vector2 operator + (const Vector2& v2) const
			{
				return Vector2(X + v2.X , Y + v2.Y);
			}


			//! Substract 2 vectors
			Vector2 operator - (const Vector2& v2) const
			{
				return Vector2(X - v2.X , Y - v2.Y);
			}


			//! Check whether 2 vectors are the same
			b8 operator == (const Vector2& v2) const
			{
				return (X ==  v2.X) && (Y == v2.Y);
			}
			

			//! Check whether 2 vectors are different
			b8 operator != (const Vector2& v2) const
			{
				return (lsz.X != (TVal)rsz.X) || (lsz.Y != (TVal)rsz.Y);
			}


			//! Multiply current vector's coordinates with a scalar
			template<class TArg>
			Vector2& operator *= (TArg scalar)
			{
				X *= scalar;	Y *= scalar; 
				return *this;
			}


			//! Divide current vector's coordinates by a scalar
			template<class TArg>
			Vector2& operator /= (TArg scalar)
			{
				X /= scalar;	Y /= scalar; 
				return *this;
			}


			//! Add current vector with another vector
			Vector2& operator += (const Vector2& sz)
			{
				X += sz.X;		Y += sz.Y;
				return *this;
			}


			//! Substract current vector with another vector
			Vector2& operator -= (const Vector2& sz)
			{
				X -= sz.X;		Y -= sz.Y;
				return *this;
			}


			//! Copy other vector's coordinates into current vector 
			Vector2& operator = (const Vector2& sz)
			{
				Set(sz.X, sz.Y);
				return *this;
			}


		public:
			union
			{
				struct { TVal X, Y; };
				TVal Coords[2];
			};
		};

		//! Signed integer 2d-vector 
		typedef Vector2<s32> Vector2s;

		//! Unsigned integer 2d-vector
		typedef Vector2<u32> Vector2u;

		//! Floating number 2d-vector
		typedef Vector2<f32> Vector2f;

		//! Double precision floating number 2d-vector
		typedef Vector2<f64> Vector2d;
	}
}

#endif//__CGE_VECTOR2_H__